/*
*
* Copyright 2015 Andrey Yakovlev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package jodtemplate.pptx.postprocessor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import jodtemplate.DomProcessor;
import jodtemplate.exception.JODTemplateException;
import jodtemplate.pptx.Configuration;
import jodtemplate.pptx.PPTXDocument;
import jodtemplate.pptx.Slide;
import jodtemplate.resource.Resources;
import jodtemplate.style.Stylizer;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.jdom2.Comment;
import org.jdom2.Content;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.Namespace;
import org.jdom2.filter.Filters;
import org.jdom2.util.IteratorIterable;
public class StylePostprocessor implements DomProcessor {
private static final String STYLIZED_KEYWORD = " stylized ";
@Override
public Document process(final Map<String, Object> context, final Document document, final Slide slide,
final Resources resources, final Configuration configuration) throws JODTemplateException {
final IteratorIterable<Element> atElements = document.getDescendants(Filters.element(PPTXDocument.T_ELEMENT,
getNamespace()));
final List<Element> atElementsList = new ArrayList<>();
while (atElements.hasNext()) {
atElementsList.add(atElements.next());
}
for (Element at : atElementsList) {
if (at.getContentSize() != 0) {
final Content content = at.getContent(0);
if (content instanceof Comment) {
final Comment comment = (Comment) content;
processComment(comment, at, slide, configuration);
}
}
}
return document;
}
private void processComment(final Comment comment, final Element at, final Slide slide,
final Configuration configuration) throws JODTemplateException {
String commentText = comment.getText();
if (commentText.startsWith(STYLIZED_KEYWORD)) {
commentText = StringUtils.removeStart(commentText, STYLIZED_KEYWORD);
final String className = StringUtils.substringBefore(commentText, ":");
commentText = StringUtils.removeStart(commentText, className + ": ");
final Stylizer stylizer = configuration.getStylizer(className);
if (stylizer == null) {
throw new JODTemplateException("Unable to find stylizer");
}
final String text = StringUtils.removeStart(commentText, " stylized: ");
final Element ar = at.getParentElement();
final Element ap = ar.getParentElement();
final int arIndex = ap.indexOf(ar);
final Element arPr = getArPrElement(ar);
final Element apPr = getApPrElement(ap);
final Element sourceApPr = ObjectUtils.clone(apPr);
cleanApPrElement(apPr);
final List<Element> stylizedElements = stylizer.stylize(text, arPr, apPr, slide);
ap.removeContent(ar);
final List<Element> remains = getRemainingElements(arIndex, ap);
for (Element el : remains) {
ap.removeContent(el);
}
final int currentApIndex = injectElementsInDocument(stylizedElements, ap, apPr, arIndex);
injectRemainsInDocument(remains, ap, sourceApPr, currentApIndex);
}
}
private int injectElementsInDocument(final List<Element> stylizedElements, final Element ap, final Element apPr,
final int arIndex) {
int index = arIndex;
final Element txBody = ap.getParentElement();
int apIndex = txBody.indexOf(ap) + 1;
boolean createNewAp = false;
Element currentAp = ap;
for (Element element : stylizedElements) {
if (element.getName().equals(PPTXDocument.P_ELEMENT)) {
currentAp = element;
txBody.addContent(apIndex, currentAp);
apIndex++;
createNewAp = true;
} else {
if (createNewAp) {
currentAp = new Element(PPTXDocument.P_ELEMENT, getNamespace());
Element apPrToAdd = ObjectUtils.clone(apPr);
if (apPrToAdd == null) {
apPrToAdd = new Element(PPTXDocument.PPR_ELEMENT, getNamespace());
}
final Element abuNone = new Element(PPTXDocument.BUNONE_ELEMENT, getNamespace());
apPrToAdd.addContent(abuNone);
currentAp.addContent(apPrToAdd);
txBody.addContent(apIndex, currentAp);
apIndex++;
createNewAp = false;
}
if (currentAp == ap) {
currentAp.addContent(index, element);
index++;
} else {
currentAp.addContent(element);
}
}
}
return apIndex;
}
private void injectRemainsInDocument(final List<Element> remains, final Element ap, final Element apPr,
final int apIndex) {
if (CollectionUtils.isNotEmpty(remains)) {
final Element txBody = ap.getParentElement();
final Element apWithRemains = new Element(PPTXDocument.P_ELEMENT, getNamespace());
if (apPr != null) {
apWithRemains.addContent(apPr);
}
apWithRemains.addContent(remains);
txBody.addContent(apIndex, apWithRemains);
}
}
private List<Element> getRemainingElements(final int fromIndex, final Element ap) {
final List<Element> remains = new ArrayList<>();
for (int i = fromIndex; i < ap.getContentSize(); ++i) {
final Content apChild = ap.getContent(i);
if (apChild instanceof Element) {
final Element apChildElement = (Element) apChild;
if (PPTXDocument.R_ELEMENT.equals(apChildElement.getName())
|| PPTXDocument.BR_ELEMENT.equals(apChildElement.getName())) {
remains.add(apChildElement);
}
}
}
return remains;
}
private Element getArPrElement(final Element ar) {
final List<Element> arPrElements = ar.getContent(Filters.element(PPTXDocument.RPR_ELEMENT, getNamespace()));
Element arPr = null;
if (CollectionUtils.isNotEmpty(arPrElements)) {
arPr = arPrElements.get(0).clone();
arPr.removeAttribute("b", getNamespace());
arPr.removeAttribute("i", getNamespace());
arPr.removeAttribute("u", getNamespace());
}
return arPr;
}
private Element getApPrElement(final Element ap) {
final List<Element> apPrElements = ap.getContent(Filters.element(PPTXDocument.PPR_ELEMENT, getNamespace()));
if (CollectionUtils.isNotEmpty(apPrElements)) {
return apPrElements.get(0).clone();
}
return null;
}
private void cleanApPrElement(final Element apPr) {
if (apPr != null) {
apPr.removeChild(PPTXDocument.BUNONE_ELEMENT, getNamespace());
apPr.removeChild(PPTXDocument.BUCHAR_ELEMENT, getNamespace());
apPr.removeChild(PPTXDocument.BUAUTONUM_ELEMENT, getNamespace());
apPr.removeChild(PPTXDocument.BUFONT_ELEMENT, getNamespace());
}
}
private Namespace getNamespace() {
return Namespace.getNamespace(PPTXDocument.DRAWINGML_NAMESPACE_PREFIX, PPTXDocument.DRAWINGML_NAMESPACE);
}
}